#include <common_modules/http_bridge/http_bridge.h>


HttpBridge::HttpBridge(){
    __cloud_aotbot_url = "http://cloud.aotbot.com:10500";
    __qiniu_url = "http://up-z2.qiniup.com";
    ros::param::param<std::string>("/cache_dir", __cache_database_dir, "/home/aoting/user_config/cache_database/");
    if(!file_manager::IsExists(__cache_database_dir)){
        file_manager::CreateDir(__cache_database_dir);
    }
    
    // ros::param::param<std::string>("/cloudplatform_url", cloudplatform_url, "http://cloud.aotbot.com:10500");
    // ros::param::param<std::string>("/cache_dir", __cache_dir, "/home/aoting/user_config/cache/");
    // ros::param::param<std::string>("/cloud_networkstate_file", __cloud_networkstate_file, "/home/aoting/user_config/cache/cloud_networkstate_file.txt");
}


HttpBridge::~HttpBridge(){
    
}


/*************************************
 * 网络状态检测
 *************************************/

// 读取缓存文件内容
std::vector<std::string> HttpBridge::ReadFile(const std::string &file_path){
    // 打印文件内容
    // std::cout << std::ifstream(file_path).rdbuf();
    std::vector<std::string> file_data;
    std::ifstream fp(file_path);
    if(!fp.is_open()){
        std::cout<<"open error"<<std::endl;
    }
    std::string read_str;
    while(std::getline(fp,read_str)){
        // std::cout<<"ReadFile:   "<<read_str<<std::endl;
        file_data.emplace_back(read_str);
    }
    fp.close();
    return file_data;
}

// 网络连接检测 设置超时2s
bool HttpBridge::getNetworkState(std::string cache_file, std::string ip, std::string port){
    std::string cmd = "echo quit | timeout --signal=9 2 telnet " 
        + ip
        + " "
        + port
        + " | tee "
        + cache_file;
    int res = std::system(cmd.c_str());
    std::vector<std::string> file_data = ReadFile(cache_file); 
    if(!file_data.empty()){
        for(auto data : file_data){
            std::string::size_type idx = data.find(std::string("Connected"));
            if(idx != std::string::npos) return true;
        }
    }
    return false;
}

// 获取云平台网络状态, 失败则重试
bool HttpBridge::getCloudNetworkState(){
    string file_path = __cache_database_dir + "cloud_network_cache.txt";
    return getNetworkState(file_path, "cloud.aotbot.com", "10500");
}

// 尝试云平台
void HttpBridge::TryPingCloudAotbot(){
    string cmd_str = "ping -c 1 cloud.aotbot.com > /dev/null 2>&1";
    int res = system(cmd_str.c_str());
}


// 尝试ping七牛云
void HttpBridge::TryPingQiniu(){
    string cmd_str = "ping -c 1 up-z2.qiniup.com > /dev/null 2>&1";
    int res = system(cmd_str.c_str());
}




/*************************************
 * HTTP请求
 *************************************/

// Json::Value -> string
string HttpBridge::Json2String(Json::Value req_data){
    Json::StreamWriterBuilder writer;
    return Json::writeString(writer, req_data);
}

// 消息转换 std::string -> Json::Value
Json::Value HttpBridge::String2JsonValue(string str_data){
    Json::Reader reader;
    Json::Value json_data;
    reader.parse(str_data, json_data); 
    return json_data;
}

// POST请求 application/json
Json::Value HttpBridge::Post_JsonData(string base_url, string path, Json::Value req_data){
    Json::Value res_data;
    httplib::Client cli(base_url);
    cli.set_connection_timeout(3.0, 0);     //设置连接超时
    cli.set_read_timeout(3, 0); // 3 seconds
    cli.set_write_timeout(5, 0); // 5 seconds
 
    std::string jsonData = Json2String(req_data);
    // cout << "jsonData: " << jsonData << endl;
    auto res = cli.Post(path, jsonData, "application/json");
    if(res && res->status == 200){
        res_data = String2JsonValue(res->body);
    }
    else{
        std::cerr << "[Post_Json] Failed to get a response. Status code: " 
            << (res ? std::to_string(res->status) : "No response") 
            << std::endl;
        // std::cout << "Response body: " << res->body << std::endl;
    }
    return res_data;
}

// POST请求 
Json::Value HttpBridge::Post_JsonData(string base_url, string path, httplib::Headers headers){
    Json::Value res_data;
    httplib::Client cli(base_url);
    cli.set_connection_timeout(3.0, 0);     //设置连接超时
    cli.set_read_timeout(3, 0); // 3 seconds
    cli.set_write_timeout(5, 0); // 5 seconds
 
    auto res = cli.Post(path, headers);
    if(res && res->status == 200){
        res_data = String2JsonValue(res->body);
    }
    else{
        std::cerr << "[Post_Json] Failed to get a response. Status code: " 
            << (res ? std::to_string(res->status) : "No response") 
            << std::endl;
        // std::cout << "Response body: " << res->body << std::endl;
    }
    return res_data;
}


// POST请求 
Json::Value HttpBridge::Post_JsonData(string base_url, string path, 
    httplib::Headers headers, Json::Value req_data){
    Json::Value res_data;
    httplib::Client cli(base_url);
    cli.set_connection_timeout(3.0, 0);     //设置连接超时
    cli.set_read_timeout(3, 0); // 3 seconds
    cli.set_write_timeout(5, 0); // 5 seconds

    std::string jsonData = Json2String(req_data);
    cout << "jsonData: " << jsonData << endl;
    auto res = cli.Post(path, headers, jsonData, "application/json");
    if(res && res->status == 200){
        res_data = String2JsonValue(res->body);
    }
    else{
        std::cerr << "[Post_Json] Failed to get a response. Status code: " 
            << (res ? std::to_string(res->status) : "No response") 
            << std::endl;
        // std::cout << "Response body: " << res->body << std::endl;
    }
    return res_data;
}


// POST请求 application/x-www-form-urlencoded
Json::Value HttpBridge::Post_FormData(string base_url, string path, Json::Value req_data){
    Json::Value res_data;
    httplib::Client cli(base_url);
    cli.set_connection_timeout(3.0, 0);     //设置连接超时
    cli.set_read_timeout(5, 0); // 3 seconds
    cli.set_write_timeout(5, 0); // 5 seconds
 
    httplib::Params params;
    // 注意，这为表单数据，暂时只转换第一层数据
    for(Json::Value::iterator bers = req_data.begin(); bers != req_data.end(); bers++){
        // std::cout << bers.key().toStyledString() << std::endl;
        // std::cout << bers.name() << std::endl;
        // params.emplace(bers.name(), Json2String(req_data[bers.name()]));
        if(req_data[bers.name()].isString()){
            params.emplace(bers.name(), req_data[bers.name()].asString());
        }
        else{
            params.emplace(bers.name(), Json2String(req_data[bers.name()]));
        }

    }
    auto res = cli.Post(path, params);
    if(res && res->status == 200){
        res_data = String2JsonValue(res->body);
    }
    else{
        std::cerr << "[Post_FormData] Failed to get a response. Status code: " 
            << (res ? std::to_string(res->status) : "No response") 
            << std::endl;
        // std::cout << "Response body: " << res->body << std::endl;
    }
    return res_data;
}

// POST请求 multipart/form-data
Json::Value HttpBridge::Post_MultipartFormData(string base_url, string path, httplib::MultipartFormDataItems form_items){
    Json::Value res_data;
    httplib::Client cli(base_url);
    cli.set_connection_timeout(3.0, 0);     //设置连接超时
    // cli.set_read_timeout(3, 0); // 3 seconds
    // cli.set_write_timeout(5, 0); // 5 seconds
 
    auto res = cli.Post(path, form_items);
    if(res && res->status == 200){
        res_data = String2JsonValue(res->body);
    }
    else{
        std::cerr << "[Post_Json] Failed to get a response. Status code: " 
            << (res ? std::to_string(res->status) : "No response") 
            << std::endl;
        // std::cout << "Response body: " << res->body << std::endl;
    }
    return res_data;
}

// PUT请求
Json::Value HttpBridge::Put_OctetStream(string base_url, string path, httplib::Headers headers, string& content){
    Json::Value res_data;
    httplib::Client cli(base_url);
    cli.set_connection_timeout(3.0, 0);     //设置连接超时
    // cli.set_read_timeout(3, 0); // 3 seconds
    // cli.set_write_timeout(5, 0); // 5 seconds

    auto res = cli.Put(path, headers, content, "application/octet-stream");
    if(res && res->status == 200){
        res_data = String2JsonValue(res->body);
    }
    else{
        std::cerr << "[Post_Json] Failed to get a response. Status code: " 
            << (res ? std::to_string(res->status) : "No response") 
            << std::endl;
        // std::cout << "Response body: " << res->body << std::endl;
    } 
    return res_data;   
}
